﻿
#if defined(_MSC_VER) /*&& defined(_WIN32) && defined(WIN32)*/
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
// SDL 关闭了也可以 除去 4996 的警告（错误）
#pragma warning(disable:4996)  //#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
// Windows 下用 cl.exe 编译的话，在代码内指定链接库的方式
#pragma comment(lib, "ws2_32.lib")
#elif defined(unix) || defined(__unix) || defined(__unix__)
//#warning You are using UNIX
#elif defined(__APPLE__) || defined(__MACH__)
//#warning You are using Mac OS X
#elif defined(__linux__)
//#warning You are using Linux
#elif defined(__FreeBSD__)
//#warning You are using FreeBSD
#else
#error Unknown OS
#endif

#include <stdio.h>

#include <thread>

const unsigned short SERVER_PORT = 4444;


int process(SOCKET _sock)
{
    int nret = 0;
    char msgBuf[256];

    do
    {
        nret = recv(_sock, msgBuf, sizeof(msgBuf), 0);
        if (nret <= 0) {
            if (0 == nret) {
                printf("远程socket 已关闭\n");
                nret = -1;
            }
            else {
                printf("recv 失败\n");
                nret = -2;
            }
            break;
        }
        
        // 注意，recv 返回的长度可能小于传递的需要接收的长度
        printf("已接收 %d 字节： %s\n", nret, msgBuf);
        nret = 0;

    } while (false);
    return nret;
}

void cmdThread(SOCKET _sock)
{
    int nret = 0;
    char cmdBuf[128];

    printf("cmdThread线程已进入...\n");

    while (true)
    {
        cmdBuf[0] = '\0';
        scanf("%s", cmdBuf);

        if (0 == stricmp(cmdBuf, "exit")) {
            char cmd[] = "exit";
            nret = send(_sock, cmd, sizeof(cmd), 0);

            break;
        }
        else {
            //
            nret = send(_sock, cmdBuf, (int)(strlen(cmdBuf) + 1), 0);
            if (SOCKET_ERROR == nret)
            {
                printf("发送失败.\n");
                break;
            }
        }
    }
}

int main(int argc, const char* argv[])
{
#if defined(_WIN32) && defined(WIN32) && defined(_MSC_VER)
    WORD wVer = MAKEWORD(2, 2);
    WSADATA data;
    WSAStartup(wVer, &data);
#endif

    SOCKET _sock = INVALID_SOCKET;
    //SOCKET _cSock = INVALID_SOCKET;
    int nret = 0;

    do
    {
        _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (INVALID_SOCKET == _sock) {
            printf("socket函数调用失败\n");
            break;
        }

        sockaddr_in _sin;
        _sin.sin_family = AF_INET;
        _sin.sin_port = htons(SERVER_PORT);
        _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

        nret = connect(_sock, (sockaddr*)&_sin, sizeof(sockaddr_in));
        if (SOCKET_ERROR == nret) {
            printf("connect 失败\n");
            break;
        }
        printf("连接服务器成功!\n");

        // 注意该对象析构时，会调用 abort()
        std::thread t(cmdThread, _sock);
        
        while (true)
        {
            fd_set fdRead;
            FD_ZERO(&fdRead);
            FD_SET(_sock, &fdRead);
            timeval t = { 0, 550 };
            int ret = select(0, &fdRead, NULL, NULL, &t);
            if (ret < 0) {
                printf("select失败，任务结束.\n");
                break;
            }

            if (FD_ISSET(_sock, &fdRead))
            {
                FD_CLR(_sock, &fdRead);

                ret = process(_sock);
                if (ret < 0)
                {
                    break;
                }
            }
            
            printf("空闲时间处理其他业务.\n");
#if 0
            cmdBuf[0] = '\0';
            scanf("%s", cmdBuf);

            if (0 == stricmp(cmdBuf, "exit")) {
                char cmd[] = "exit";
                nret = send(_sock, cmd, sizeof(cmd), 0);

                break;
            }
            else {
                //
                nret = send(_sock, cmdBuf, strlen(cmdBuf) + 1, 0);
                if (SOCKET_ERROR == nret)
                {
                    printf("发送失败.\n");
                    break;
                }
            }

            char msgBuf[256];
            nret = recv(_sock, msgBuf, sizeof(msgBuf), 0);
            if (nret <= 0) {
                if (0 == nret)
                    printf("远程socket 已关闭\n");
                else
                    printf("recv 失败\n");

                break;
            }
            else {
                // 注意，recv 返回的长度可能小于传递的需要接收的长度
                printf("已接收 %d 字节： %s\n", nret, msgBuf);
            }
#endif

        }

        getchar();
    } while (0);

    if (INVALID_SOCKET != _sock)
        closesocket(_sock);

#if defined(_WIN32) && defined(WIN32) && defined(_MSC_VER)
    WSACleanup();
#endif

    printf("程序退出...\n");
    getchar();
    return 0;
}